package com.linkoog.devtools.archive;

import com.intellij.ide.highlighter.ArchiveFileType;
import com.linkoog.devtools.archive.filesystem.ArchiveBasedFileSystem;
import com.linkoog.devtools.archive.filesystem.zip.ArchiveFileTypeExt;
import com.linkoog.devtools.archive.filesystem.gz.GZFileSystem;
import com.linkoog.devtools.archive.filesystem.gz.GZFileType;
import com.linkoog.devtools.archive.filesystem.sevenzip.SevenZipFileSystem;
import com.linkoog.devtools.archive.filesystem.sevenzip.SevenZipFileType;
import com.linkoog.devtools.archive.filesystem.tar.TarFileSystem;
import com.linkoog.devtools.archive.filesystem.tar.TarFileType;
import com.linkoog.devtools.archive.filesystem.tar.TarGzFileType;
import com.linkoog.devtools.archive.filesystem.zip.ZipFileSystem;
import com.linkoog.devtools.archive.nodes.PsiDirectoryNodeWrapper;
import com.linkoog.devtools.archive.util.CoreUtil;
import com.intellij.ide.projectView.TreeStructureProvider;
import com.intellij.ide.projectView.ViewSettings;
import com.intellij.ide.projectView.impl.nodes.PsiFileNode;
import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.Collection;
import java.util.stream.Collectors;

public class ArchiveTreeProvider implements TreeStructureProvider {

    @NotNull
    @Override
    public Collection<AbstractTreeNode<?>> modify(@NotNull AbstractTreeNode<?> parent, @NotNull Collection<AbstractTreeNode<?>> children, ViewSettings settings) {
        return children.stream().map(node -> {
            if (! (node instanceof PsiFileNode psiFileNode)) return node;

            VirtualFile virtualFile = psiFileNode.getVirtualFile();
            if (virtualFile == null || !virtualFile.isValid()) return node;

            Project project = parent.getProject();
            try {
                boolean isNestedFile = false;
                // copy the nested file into temporary folder if it should be.
                if (ArchiveBasedFileSystem.isNestedFile(virtualFile.getPath())) {
                    File targetFile = CoreUtil.getTempFilePath(virtualFile).toFile();
                    if (! targetFile.exists()) {
                        targetFile.getParentFile().mkdirs();
                        try (InputStream inputStream = virtualFile.getInputStream()){
                            Files.copy(inputStream, targetFile.toPath());
                        }
                    }

                    VirtualFile targetVf = LocalFileSystem.getInstance().findFileByIoFile(targetFile);
                    if (targetVf != null) {
                        virtualFile = targetVf;
                        isNestedFile = true;
                    }
                }

                VirtualFile archiveFile = null;
                FileType fileType = virtualFile.getFileType();
                if (fileType.equals(ArchiveFileType.INSTANCE) || fileType.equals(ArchiveFileTypeExt.INSTANCE)) {
                    archiveFile = ZipFileSystem.getInstance().getRootByLocal(virtualFile);
                } else if (fileType.equals(GZFileType.INSTANCE) || fileType.equals(TarGzFileType.INSTANCE)) {
                    archiveFile = GZFileSystem.getInstance().getRootByLocal(virtualFile);
                } else if (fileType.equals(TarFileType.INSTANCE)) {
                    archiveFile = TarFileSystem.getInstance().getRootByLocal(virtualFile);
                } else if (fileType.equals(SevenZipFileType.INSTANCE)) {
                    archiveFile = SevenZipFileSystem.getInstance().getRootByLocal(virtualFile);
                }

                if (archiveFile != null) {
                    return new PsiDirectoryNodeWrapper(project, psiFileNode.getValue(), settings, isNestedFile, archiveFile);
                }
            }catch (Throwable ignored){
            }
            return node;
        }).collect(Collectors.toList());
    }



}